//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// OziExplorer PLT (tracks) export.
//

# include "StdAfx.h"
# include "Save.h"
# include "Map.h"
# include "Status.h"
# include "SaveFileDlg.h"
# include "FileWriter.h"
# include "fast_floor.h"
# include "Options.h"
# include "Globals.h"

class COziPltExport : public CMapSaver {
  public:
	virtual bool CanSave (const map_t & _map) {return true;}
	virtual bool Save (HANDLE _hFile, const char * _strFileName, const map_t & _map);

  private:
	bool _Save (HANDLE _hFile, const map_t & _map);
};

DECLARE_WPTRK_EXPORT (COziPltExport, "ozi-plt", "plt", "OziExplorer tracks (*.plt)");

bool COziPltExport::Save (HANDLE _hFile, const char * _strFileName, const map_t & _map) {
	if (_hFile) {
		return _Save (_hFile, _map);
	} else {
		//
		// Prepare file name.
		//
		char strFileName [MAX_PATH + 1];
		::strncpy (strFileName, _strFileName, MAX_PATH);
		strFileName [MAX_PATH] = '\0';
		if (! SaveFileDlg ("plt", "OziExplorer track (*.plt)\0*.plt\0", strFileName))
			return false;

		//
		// Open the file.
		//
		const CFileForWrite hFile (strFileName);
		if (! hFile.IsValid ()) {
			ErrorMsgBox ("Can't create file:\n %s", strFileName);
			return false;
		}

		return _Save (hFile, _map);
	}
}

bool COziPltExport::_Save (HANDLE _hFile, const map_t & _map) {
	//
	// Prepare data.
	//

	//
	string_t strName;
	size_t cTotalPoints = 0;
	int nTrackWidth = GetDefaultTrackWidth ();
	DWORD dwTrackColor = GetDefaultTrackColor ();

	const layer_t & layer = _map.layers [rkPolyline];
	const rgns_t & rgns = layer.rgns;
	rgns_t::const_iterator iRgn;
	for (iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn) {
		const rgn_t & rgn = * iRgn;
		if (rgn.IsDeleted () || ! rgn.IsTrack ())
			continue;

		if (strName.empty () && ! rgn.strLabel.empty ())
			strName = rgn.strLabel;

		const track_info_t * const pExtra = rgn.pExtra ? rgn.pExtra->wtr.track () : NULL;
		if (pExtra && (pExtra->wFlags & track_info_t::defLineColor))
			dwTrackColor = pExtra->colLine;
		if (pExtra && (pExtra->wFlags & track_info_t::defLineWidth))
			nTrackWidth = pExtra->wLineWidth;

		for (size_t cElement = 0; cElement < rgn.elements.size (); ++ cElement) {
			const rgn_element_t & element = rgn.elements [cElement];
			if (element.bDeleted)
				continue;
			const points_t & points = element.points;
			const size_t cPoints = points.size ();
			cTotalPoints += cPoints;
		}
	}

	// Remove commas from the name.
	string_t strName2;
	for (size_t c = 0; c < strName.size (); ++ c) {
		if (strName [c] == ',')
			continue;
		strName2.append (1, strName [c]);
	}
	strName2.swap (strName);

	CFileWriter fw (_hFile);
	fw.SetFPrecision (6);

	//
	// Write the file.
	//
	SetProgressStatus (0);

	fw.WriteS (
		"OziExplorer Track Point File Version 2.1\r\n"
		"WGS 84\r\n"
		"Altitude is in Feet\r\n"
		"Reserved 3\r\n"
	);
	fw.WriteFmt ("0,%d,%d,%s,0,0,0,%d\r\n", nTrackWidth, dwTrackColor, strName.c_str (), dwTrackColor);
	fw.WriteU (cTotalPoints);
	fw.WriteS ("\r\n");

	size_t cRgn = 0;
	for (iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn, ++ cRgn) {
		const rgn_t & rgn = * iRgn;
		if (rgn.IsDeleted () || ! rgn.IsTrack ())
			continue;

		// Save track.
		for (size_t cElement = 0; cElement < rgn.elements.size (); ++ cElement) {
			const rgn_element_t & element = rgn.elements [cElement];
			if (element.bDeleted)
				continue;
			const points_t & points = element.points;
			const size_t cPoints = points.size ();
			if (cPoints == 0)
				continue;

			const track_info_t * const pExtra = rgn.pExtra ? rgn.pExtra->wtr.track () : NULL;
			const rgn_element_extra_t * const pExtra2 = element.pExtra ? & * element.pExtra : NULL;

			for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
				int nAltitudeInFeet = -777;
				DATE dtTime = 0;
				char strDate [32] = "  ";
				char strTime [32] = "  ";
				if (pExtra && cPoint < pExtra2->TrackPoints.size ()) {
					const trackpoint_info_t & PointExtra = pExtra2->TrackPoints [cPoint];

					if (PointExtra.wFlags & trackpoint_info_t::defAltitude)
						nAltitudeInFeet = fast_floor (PointExtra.fAltitude*c_feet_per_m + .5f);

					if (PointExtra.wFlags & trackpoint_info_t::defTime) {
						dtTime = PointExtra.dtTime;

						SYSTEMTIME st;
						::VariantTimeToSystemTime (dtTime, & st);
						::GetDateFormat (LOCALE_USER_DEFAULT, 0, & st, "dd-MMM-yy", strDate, sizeof (strDate)/sizeof (strDate [0]));
						::GetTimeFormat (LOCALE_USER_DEFAULT, 0, & st, NULL, strTime, sizeof (strTime)/sizeof (strTime [0]));
					}
				}

				// Position.
				fw.SetFPrecision (6);
				fw.WriteF (points [cPoint].y);
				fw.WriteC (',');
				fw.WriteF (points [cPoint].x);
				fw.WriteC (',');

				// New track segment mark.
				fw.WriteC (cPoint == 0 ? '1' : '0');
				fw.WriteC (',');

				// Altitude.
				if (nAltitudeInFeet < 0)
					fw.WriteC ('-');
				fw.WriteU (::labs (nAltitudeInFeet));
				fw.WriteC (',');

				// Date and Time.
				fw.SetFPrecision (7); // NOTE: this precision is important to keep up to 9 ms.
				fw.WriteDF (dtTime);
				fw.WriteC (',');
				fw.WriteS (strDate);
				fw.WriteC (',');
				fw.WriteS (strTime);
				fw.WriteS ("\r\n");
			}
		}

		SetProgressStatus (fast_floor (100.f*cRgn/layer.cRgns + .5f));
	}

	fw.FlushBuffer ();

	SetProgressStatus (100);

	if (fw.GetOverflow ())
		ErrorMsgBox ("File has been written partialy.\nThis may be caused by disk overflow.");

	return true;
}
